import tkinter as tk
from tkinter import messagebox
import threading
import time
import cv2
import json
from PIL import Image, ImageTk
from hashdata import hash_dataframe
from decode import QRCodeDataReconstructor
from visualizer import QRDecodeVisualizer
from config_manager import ConfigManager

class IntegratedQRDecoder:
    """
    集成的二维码解码器类
    将QRCodeDataReconstructor与可视化界面结合，实现实时解码监控
    """
    
    def __init__(self, root):
        """
        初始化集成解码器
        
        参数:
            root: tkinter根窗口
        """
        self.root = root
        
        # 创建QRCodeDataReconstructor实例
        try:
            self.reconstructor = QRCodeDataReconstructor()
            
            # 检查检测器是否初始化成功
            if self.reconstructor.detector is None:
                messagebox.showwarning("检测器初始化警告", "无法初始化真实的二维码检测器，程序可能无法正常工作")
            # 移除成功初始化的弹窗显示
            
            # 替换原始的scan_qr_code_from_camera方法以支持实时更新
            self.original_scan_method = self.reconstructor.scan_qr_code_from_camera
            self.reconstructor.scan_qr_code_from_camera = self.custom_scan_method
            
            # 初始化可视化器
            self.visualizer = QRDecodeVisualizer(root, self.reconstructor)
            # 标记为集成模式，避免模拟摄像头画面干扰
            self.visualizer.is_integrated_mode = True
            
            # 不再使用width和height参数配置Label
            # 尺寸控制将在update_camera_frame方法中通过调整图像大小实现
            
            # 设置回调函数
            self.setup_callbacks()
            
        except Exception as e:
            messagebox.showerror("初始化失败", f"初始化过程中出错: {str(e)}")
            # 不再销毁窗口，而是继续运行但可能功能受限
    
    def setup_callbacks(self):
        """设置回调函数，用于在解码过程中更新界面"""
        # 替换visualizer中的decode_process方法
        self.visualizer.decode_process = self.decode_process
    
    def custom_scan_method(self, capture_interval: float = 1.0):
        """
        自定义的扫码方法，在原始方法基础上添加界面更新回调
        实现基于task_hash的任务管理功能
        
        参数:
            capture_interval: 拍摄间隔时间（秒）
        """
        # 从配置文件获取扫码频率
        capture_interval = ConfigManager.get_capture_interval()
        self.visualizer.log_message(f"从配置文件读取扫码频率: {capture_interval} 秒")
        
        # 禁用OpenCV的错误打印，避免显示不必要的错误消息
        try:
            # 尝试使用LOG_LEVEL_SILENT (较新版本OpenCV)
            cv2.setLogLevel(cv2.LOG_LEVEL_SILENT)
        except AttributeError:
            try:
                # 尝试使用数字常量 (较旧版本OpenCV)
                cv2.setLogLevel(0)  # 0 通常对应SILENT或FATAL级别
            except Exception:
                # 如果都失败，忽略错误
                pass
        
        # 尝试打开摄像头，使用不同的后端
        cap = None
        
        # 尝试使用DirectShow后端
        try:
            cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
            if cap.isOpened():
                self.visualizer.log_message("成功使用DirectShow后端打开摄像头")
            else:
                # 尝试使用默认后端
                cap = cv2.VideoCapture(0)
                if cap.isOpened():
                    self.visualizer.log_message("成功使用默认后端打开摄像头")
        except Exception as e:
            self.visualizer.log_message(f"尝试打开摄像头时出错: {str(e)}")
            cap = None
        
        # 如果摄像头无法打开，显示错误
        if cap is None or not cap.isOpened():
            self.visualizer.log_message("错误: 无法打开真实摄像头")
            return None
        
        # 初始化变量
        decoded_data = []
        self.visualizer.total_chunks = 100  # 默认值
        self.visualizer.decoded_chunks = []
        self.visualizer.task_hash = ""
        task_completed = False  # 任务完成标志
        first_scan = True
        last_capture_time = time.time()
        
        self.visualizer.log_message(f"开始按固定间隔拍摄，间隔时间: {capture_interval}秒")
        
        while self.visualizer.is_decoding:
            # 检查工作时间（如果启用）
            if self.reconstructor.is_in_work_time:
                if not self.reconstructor.is_currently_in_work_time():
                    current_time_str = time.strftime('%H:%M:%S')
                    start_time_str = f"{self.reconstructor.work_start_time[0]:02d}:{self.reconstructor.work_start_time[1]:02d}"
                    end_time_str = f"{self.reconstructor.work_end_time[0]:02d}:{self.reconstructor.work_end_time[1]:02d}"
                    
                    self.visualizer.log_message(f"当前非工作时间: {current_time_str} (工作时间: {start_time_str} - {end_time_str})")
                    time.sleep(5)  # 减少CPU占用
                    continue
            
            # 检查是否到达拍摄时间间隔
            current_time = time.time()
            if current_time - last_capture_time >= capture_interval:
                last_capture_time = current_time
                
                # 读取实际摄像头画面
                try:
                    ret, frame = cap.read()
                    if not ret or frame is None:
                        self.visualizer.log_message("警告: 无法读取摄像头画面")
                        continue
                    
                    # 更新摄像头画面
                    self.update_camera_frame_with_actual(frame)
                except Exception as e:
                    self.visualizer.log_message(f"读取摄像头帧时出错: {str(e)}")
                    # 如果持续出错，释放资源并返回
                    cap.release()
                    self.visualizer.log_message("读取摄像头帧持续出错，已释放资源")
                    return None
                
                # 扫描二维码
                try:
                    results, points = self.reconstructor.detector.detectAndDecode(frame)
                    
                    # 处理扫描结果
                    if results and len(results) > 0:
                        self.visualizer.log_message(f"扫描到二维码: {json.loads(results[0])['task_hash']}")
                        
                        # 处理每个二维码
                        for result in results:
                            try:
                                # 解析JSON数据
                                data_dict = json.loads(result)
                                current_task_hash = data_dict['task_hash']
                                current_total_chunks = data_dict['total_chunks']
                                
                                # 首次扫描或遇到新任务
                                if first_scan:
                                    first_scan = False
                                    self.visualizer.task_hash = current_task_hash
                                    self.visualizer.total_chunks = current_total_chunks
                                    self.visualizer.decoded_chunks = []
                                    decoded_data = []
                                    task_completed = False
                                    self.visualizer.log_message(f"开始新任务：{current_task_hash}")
                                    # 更新任务时间
                                    self.visualizer.update_task_time(current_task_hash)
                                    self.update_ui_on_main_thread()
                                # 检查是否是同一任务的二维码
                                elif self.visualizer.task_hash == current_task_hash:
                                    # 如果任务已完成，提示用户
                                    if task_completed:
                                        self.visualizer.log_message(f"此任务已完成，等待下一个扫码任务")
                                        continue
                                        
                                    # 如果还有未解码的块
                                    if len(self.visualizer.decoded_chunks) < self.visualizer.total_chunks:
                                        current_chunk = data_dict['current_chunk']
                                        # 如果当前块未被解码过
                                        if current_chunk not in self.visualizer.decoded_chunks:
                                            # 记录已解码的块索引
                                            self.visualizer.decoded_chunks.append(current_chunk)
                                            decoded_data.append(data_dict)
                                            
                                            self.visualizer.log_message(f"已解码块 {current_chunk}/{self.visualizer.total_chunks}")
                                            self.update_ui_on_main_thread()
                                            
                                            # 检查是否所有块都已解码
                                            if len(self.visualizer.decoded_chunks) == self.visualizer.total_chunks:
                                                self.visualizer.log_message("所有块解码完成，开始数据重建...")
                                                
                                                # 重建数据
                                                try:
                                                    df = self.reconstructor.reconstruct_dataframe(decoded_data)
                                                    
                                                    # 验证数据
                                                    hash_value = hash_dataframe(df)
                                                    if hash_value == self.visualizer.task_hash:
                                                        self.visualizer.log_message("数据重建成功！验证通过！")
                                                        task_completed = True
                                                        
                                                        # 保存到数据库
                                                        collection_name = f"qr_data_{self.visualizer.task_hash[:10]}"
                                                        self.visualizer.log_message(f"正在保存数据到集合: {collection_name}")
                                                        
                                                        save_success = self.reconstructor.insert_dataframe_to_mongo(df, collection_name)
                                                        if save_success:
                                                            self.visualizer.log_message("数据已成功保存到MongoDB")
                                                            self.visualizer.update_db_status("成功")
                                                            self.visualizer.update_status("任务完成")
                                                        else:
                                                            error_msg = "数据库连接失败"
                                                            self.visualizer.log_message(f"错误: 数据保存到MongoDB失败 - {error_msg}")
                                                            self.visualizer.update_db_status("失败", error_msg)
                                                            self.visualizer.update_status("保存失败")
                                                    else:
                                                        self.visualizer.log_message("错误: 数据哈希验证失败")
                                                        self.visualizer.update_db_status("失败", "哈希验证失败")
                                                        self.visualizer.update_status("验证失败")
                                                        
                                                except Exception as e:
                                                    error_msg = str(e)
                                                    self.visualizer.log_message(f"数据重建出错: {error_msg}")
                                                    self.visualizer.update_db_status("失败", "数据重建错误")
                                                    self.visualizer.update_status("重建失败")
                                    else:
                                        # 如果任务未标记为完成但所有块都已处理，标记为完成
                                        if not task_completed:
                                            task_completed = True
                                            self.visualizer.log_message("当前任务已完成！")
                                            self.visualizer.update_status("任务完成")
                                            # 如果任务完成但数据库状态还是待插入，说明没有保存成功
                                            if self.visualizer.db_status == "待插入":
                                                self.visualizer.update_db_status("失败", "任务完成但未保存")
                                else:  # 发现新任务
                                    self.visualizer.log_message(f"发现新任务码：{current_task_hash}")
                                    # 重置状态，准备新任务
                                    self.visualizer.task_hash = current_task_hash
                                    self.visualizer.total_chunks = current_total_chunks
                                    self.visualizer.decoded_chunks = []
                                    decoded_data = []
                                    task_completed = False
                                    self.visualizer.log_message("开始新的扫码任务")
                                    
                                    # 立即处理新任务的当前块
                                    current_chunk = data_dict['current_chunk']
                                    self.visualizer.decoded_chunks.append(current_chunk)
                                    decoded_data.append(data_dict)
                                    self.visualizer.log_message(f"已解码块 {current_chunk}/{self.visualizer.total_chunks}")
                                    self.update_ui_on_main_thread()
                                    
                            except json.JSONDecodeError:
                                self.visualizer.log_message("警告: 二维码数据不是有效的JSON格式")
                            except Exception as e:
                                self.visualizer.log_message(f"处理二维码数据时出错: {str(e)}")
                except Exception as e:
                    self.visualizer.log_message(f"扫描二维码时出错: {str(e)}")
            
            # 短暂休眠减少CPU占用
            time.sleep(0.05)
        
        # 释放资源
        cap.release()
        return None
    
    def update_camera_frame_with_actual(self, frame):
        """
        使用实际摄像头画面更新界面 - 使用适合7英寸屏幕的固定尺寸
        
        参数:
            frame: OpenCV格式的图像帧
        """
        # 设置摄像头画面尺寸为窗体的四分之一（约400x240）
        fixed_width, fixed_height = 400, 240
        
        # 在主线程上更新界面
        def update():
            try:
                # 转换OpenCV图像格式为PIL格式
                img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                img_pil = Image.fromarray(img_rgb)
                
                # 调整为固定尺寸
                img_pil = img_pil.resize((fixed_width, fixed_height), Image.LANCZOS)
                
                # 转换为Tkinter可用的图像
                img_tk = ImageTk.PhotoImage(image=img_pil)
                
                # 更新标签图像
                self.visualizer.camera_label.config(image=img_tk)
                self.visualizer.camera_label.image = img_tk
            except Exception as e:
                print(f"更新摄像头画面时出错: {str(e)}")
        
        # 确保在主线程执行
        self.root.after(0, update)
    
    def update_ui_on_main_thread(self):
        """在主线程上更新UI元素"""
        def update():
            progress = len(self.visualizer.decoded_chunks) / self.visualizer.total_chunks * 100
            self.visualizer.update_progress(progress)
            self.visualizer.update_task_info()
        
        self.root.after(0, update)      
    
    def reset_decoding_state(self):
        """重置解码状态"""
        self.visualizer.decoded_chunks = []
        self.visualizer.update_db_status("待插入")
        self.update_ui_on_main_thread()
    
    def decode_process(self):
        """实际的解码处理过程"""
        try:
            # 调用修改后的扫码方法
            self.visualizer.update_status("解码中...")
            self.custom_scan_method(capture_interval=1.0)
        except Exception as e:
            self.visualizer.log_message(f"解码过程出错: {str(e)}")
            self.visualizer.update_status("错误")
        finally:
            if self.visualizer.is_decoding:
                self.visualizer.is_decoding = False

# 已在文件开头导入所有必要的库

def main():
    # 创建Tkinter根窗口
    root = tk.Tk()
    
    # 创建集成解码器
    integrated_decoder = IntegratedQRDecoder(root)
    
    # 启动主循环
    root.mainloop()

if __name__ == "__main__":
    main()